﻿
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;

using DirectN;

using Microsoft.Graphics.Canvas.Effects;
using Microsoft.Web.WebView2.Core;

using Windows.UI.Composition;

using WinRT;


namespace WinFormsApp2;

public partial class Form1 : Form
{
    protected IntPtr hwnd;
    object dispatcherQueue;
    protected ContainerVisual containerVisual;
    protected Compositor compositor;
    private IComObject<ICompositionTarget> compositionTarget;

    public Visual RootVisual
    {
        set
        {
            if (compositor == null)
            {
                InitComposition();
            }

            compositionTarget.Object.Root = value;

        }
    }

    protected override CreateParams CreateParams
    {
        get
        {
            var cp = base.CreateParams;

            cp.ExStyle |= (int)0x200000u;


            return cp;
        }
    }

    private object InitializeCoreDispatcher()
    {
        DispatcherQueueOptions options = new DispatcherQueueOptions();
        options.apartmentType = DISPATCHERQUEUE_THREAD_APARTMENTTYPE.DQTAT_COM_STA;
        options.threadType = DISPATCHERQUEUE_THREAD_TYPE.DQTYPE_THREAD_CURRENT;
        options.dwSize = Marshal.SizeOf(typeof(DispatcherQueueOptions));

        object queue = null;
        CreateDispatcherQueueController(options, out queue);
        return queue;
    }

    private SpriteVisual _hostVisual;



    private ContainerVisual _webviewVisual;


    private void InitComposition()
    {

        compositor = new Compositor();
        var interop = compositor.As<DirectN.ICompositorDesktopInterop>();

        interop.CreateDesktopWindowTarget(hwnd, false, out var target);

        compositionTarget = new ComObject<ICompositionTarget>((ICompositionTarget)target);


        


        containerVisual = compositor.CreateContainerVisual();


        

        _webviewVisual = compositor.CreateSpriteVisual();



        _hostVisual = compositor.CreateSpriteVisual();

        _hostVisual.Size = new System.Numerics.Vector2(ClientSize.Width, ClientSize.Height);

        var blurEffect = new GaussianBlurEffect
        {
            Name = "Blur",
            BlurAmount = 40.0f,
            BorderMode = EffectBorderMode.Hard,
            Optimization = EffectOptimization.Quality,
            Source = new CompositionEffectSourceParameter("source"),
        };

        var factory = compositor.CreateEffectFactory(blurEffect, null);
        var effectBrush = factory.CreateBrush();
               

        effectBrush.SetSourceParameter("source", compositor.CreateBackdropBrush());
        
        _hostVisual.Brush = effectBrush;


        //_backVisual = compositor.CreateSpriteVisual();

        //_backVisual.Size = new System.Numerics.Vector2(ClientSize.Width, ClientSize.Height);

        //var bb = compositor.CreateColorBrush(Windows.UI.Color.FromArgb(66, 99, 166, 233));

        
        //_backVisual.Brush = bb;

        


        //_hostVisual.IsVisible = true;


        containerVisual.Children.InsertAtBottom(_hostVisual);


        //containerVisual.Children.InsertAtBottom(_backVisual);


        //containerVisual.Children.InsertAtBottom(_hostVisual);



        containerVisual.Children.InsertAtTop(_webviewVisual);




        RootVisual = containerVisual;
    }

    protected override void OnResize(EventArgs e)
    {
        base.OnResize(e);

        if (_hostVisual == null) return;

        
        

        

        if (_controller != null)
        {
            //Debug.WriteLine( "SIZED:");
            //Debug.WriteLine(_webviewVisual.Size);

            _webviewVisual.Size = new System.Numerics.Vector2(ClientSize.Width, ClientSize.Height);
            _controller.Bounds = new Rectangle(0,0, ClientSize.Width /2, ClientSize.Height /2);

            //Debug.WriteLine(_webviewVisual.Size);
        }

        _hostVisual.Size = new System.Numerics.Vector2(ClientSize.Width, ClientSize.Height);
        //_backVisual.Size = new System.Numerics.Vector2(ClientSize.Width, ClientSize.Height);


    }

    protected override void OnHandleCreated(EventArgs e)
    {
        base.OnHandleCreated(e);


        // Get the window handle.
        hwnd = Handle;


        dispatcherQueue = InitializeCoreDispatcher();

        InitComposition();

        InitWebView2();

        // Get compositor and target for hwnd.

    }

    public Form1()
    {



        InitializeComponent();


    }

    CoreWebView2Environment? _environment;
    CoreWebView2CompositionController? _controller;

    private async void InitWebView2()
    {
        var env = _environment = await CoreWebView2Environment.CreateAsync();



        if (env == null) throw new InvalidOperationException("WebView2Environment is null");

        _controller = await env.CreateCoreWebView2CompositionControllerAsync(Handle);

        if (_webviewVisual != null)
        {
            _controller.RootVisualTarget = _webviewVisual;
        }



        _controller.Bounds = ClientRectangle;

        _controller.BoundsMode = CoreWebView2BoundsMode.UseRawPixels;



        _controller.CoreWebView2.DOMContentLoaded += CoreWebView2_DOMContentLoaded;
        

        _controller.CoreWebView2.Navigate("https://cn.bing.com");



    }

    private void CoreWebView2_DOMContentLoaded(object? sender, CoreWebView2DOMContentLoadedEventArgs e)
    {
    }

    private void Form1_Click(object sender, EventArgs e)
    {
        Random random = new Random();
        float size = random.Next(50, 150);
        float offsetX = random.Next(0, (int)(ClientSize.Width - size));
        float offsetY = random.Next(0, (int)(ClientSize.Height / 2 - size));


        var visual = compositor.CreateSpriteVisual();
        visual.Size = new System.Numerics.Vector2(size, size);
        visual.Brush = compositor.CreateColorBrush(GetRandomColor());
        visual.Offset = new System.Numerics.Vector3(offsetX, offsetY, 0);





        containerVisual.Children.InsertAtTop(visual);

        
        AnimateSquare(visual, 3);


    }

    private void AnimateSquare(SpriteVisual visual, int delay)
    {
        float offsetX = (float)(visual.Offset.X);

        Vector3KeyFrameAnimation animation = compositor.CreateVector3KeyFrameAnimation();
        float bottom = Height - visual.Size.Y;
        animation.InsertKeyFrame(1f, new System.Numerics.Vector3(offsetX, bottom, 0f));
        animation.Duration = TimeSpan.FromSeconds(2);
        animation.DelayTime = TimeSpan.FromSeconds(delay);
        visual.StartAnimation("Offset", animation);
    }

    private Windows.UI.Color GetRandomColor()
    {
        Random random = new Random();
        byte r = (byte)random.Next(0, 255);
        byte g = (byte)random.Next(0, 255);
        byte b = (byte)random.Next(0, 255);
        return Windows.UI.Color.FromArgb(255, r, g, b);
    }


    #region PInvoke declarations

    //typedef enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
    //{
    //    DQTAT_COM_NONE,
    //    DQTAT_COM_ASTA,
    //    DQTAT_COM_STA
    //};
    internal enum DISPATCHERQUEUE_THREAD_APARTMENTTYPE
    {
        DQTAT_COM_NONE = 0,
        DQTAT_COM_ASTA = 1,
        DQTAT_COM_STA = 2
    };

    //typedef enum DISPATCHERQUEUE_THREAD_TYPE
    //{
    //    DQTYPE_THREAD_DEDICATED,
    //    DQTYPE_THREAD_CURRENT
    //};
    internal enum DISPATCHERQUEUE_THREAD_TYPE
    {
        DQTYPE_THREAD_DEDICATED = 1,
        DQTYPE_THREAD_CURRENT = 2,
    };

    //struct DispatcherQueueOptions
    //{
    //    DWORD dwSize;
    //    DISPATCHERQUEUE_THREAD_TYPE threadType;
    //    DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
    //};
    [StructLayout(LayoutKind.Sequential)]
    internal struct DispatcherQueueOptions
    {
        public int dwSize;

        [MarshalAs(UnmanagedType.I4)]
        public DISPATCHERQUEUE_THREAD_TYPE threadType;

        [MarshalAs(UnmanagedType.I4)]
        public DISPATCHERQUEUE_THREAD_APARTMENTTYPE apartmentType;
    };

    //HRESULT CreateDispatcherQueueController(
    //  DispatcherQueueOptions options,
    //  ABI::Windows::System::IDispatcherQueueController** dispatcherQueueController
    //);
    [DllImport("coremessaging.dll", EntryPoint = "CreateDispatcherQueueController", CharSet = CharSet.Unicode)]
    internal static extern IntPtr CreateDispatcherQueueController(DispatcherQueueOptions options,
                                             [MarshalAs(UnmanagedType.IUnknown)]
                                            out object dispatcherQueueController);

    #endregion PInvoke declarations
}



#region COM Interop

/*
#undef INTERFACE
#define INTERFACE ICompositorDesktopInterop
    DECLARE_INTERFACE_IID_(ICompositorDesktopInterop, IUnknown, "29E691FA-4567-4DCA-B319-D0F207EB6807")
    {
        IFACEMETHOD(CreateDesktopWindowTarget)(
            _In_ HWND hwndTarget,
            _In_ BOOL isTopmost,
            _COM_Outptr_ IDesktopWindowTarget * *result
            ) PURE;
    };
*/
[ComImport]
[Guid("29E691FA-4567-4DCA-B319-D0F207EB6807")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface ICompositorDesktopInterop
{
    void CreateDesktopWindowTarget(IntPtr hwndTarget, bool isTopmost, out IntPtr test);
}

//[contract(Windows.Foundation.UniversalApiContract, 2.0)]
//[exclusiveto(Windows.UI.Composition.CompositionTarget)]
//[uuid(A1BEA8BA - D726 - 4663 - 8129 - 6B5E7927FFA6)]
//interface ICompositionTarget : IInspectable
//{
//    [propget] HRESULT Root([out] [retval] Windows.UI.Composition.Visual** value);
//    [propput] HRESULT Root([in] Windows.UI.Composition.Visual* value);
//}

[ComImport]
[Guid("A1BEA8BA-D726-4663-8129-6B5E7927FFA6")]
//[InterfaceType(ComInterfaceType.InterfaceIsIInspectable)]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]

public interface ICompositionTarget : DirectN.IInspectable
{
    [PreserveSig]
    new HRESULT GetIids(out int iidCount, out IntPtr iids);

    [PreserveSig]
    new HRESULT GetRuntimeClassName([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(HStringMarshaler))] out string className);

    [PreserveSig]
    new HRESULT GetTrustLevel(out DirectN.TrustLevel trustLevel);

    Windows.UI.Composition.Visual Root
    {
        get;
        set;
    }
}

#endregion COM Interop